"""
IP 地址处理工具模块

提供获取客户端真实 IP 地址的功能，支持代理服务器和负载均衡器场景
"""

import ipaddress
import os
from functools import lru_cache
from typing import Optional

from fastapi import Request
from qqwry import QQwry


def get_client_ip(request: Request) -> Optional[str]:
    """
    获取客户端真实 IP 地址

    支持多种代理场景：
    1. 直接访问
    2. 反向代理（Nginx/Apache）
    3. 负载均衡器（AWS ELB/ALB）
    4. CDN 服务

    Args:
        request: FastAPI 请求对象

    Returns:
        Optional[str]: 客户端 IP 地址，如果无法获取则返回 None
    """
    # 优先级：X-Forwarded-For > X-Real-IP > remote_addr
    x_forwarded_for = request.headers.get("X-Forwarded-For")
    if x_forwarded_for:
        # X-Forwarded-For 可能包含多个 IP（客户端IP, 代理1IP, 代理2IP...）
        ips = [ip.strip() for ip in x_forwarded_for.split(",")]
        # 第一个 IP 是客户端真实 IP
        client_ip = ips[0]
        if _is_valid_ip(client_ip):
            return client_ip

    x_real_ip = request.headers.get("X-Real-IP")
    if x_real_ip and _is_valid_ip(x_real_ip):
        return x_real_ip

    # 直接连接时的客户端 IP
    if request.client and request.client.host:
        client_ip = request.client.host
        if _is_valid_ip(client_ip):
            return client_ip

    return None


def get_client_ip_with_proxy_info(request: Request) -> dict:
    """
    获取客户端 IP 及代理信息

    Args:
        request: FastAPI 请求对象

    Returns:
        dict: 包含 IP 地址和代理链信息的字典
    """
    result = {"client_ip": None, "proxy_chain": [], "is_behind_proxy": False}

    # 检查 X-Forwarded-For
    x_forwarded_for = request.headers.get("X-Forwarded-For")
    if x_forwarded_for:
        ips = [ip.strip() for ip in x_forwarded_for.split(",")]
        result["proxy_chain"] = ips
        result["is_behind_proxy"] = True

        # 第一个 IP 是客户端真实 IP
        if ips and _is_valid_ip(ips[0]):
            result["client_ip"] = ips[0]
            return result

    # 检查 X-Real-IP
    x_real_ip = request.headers.get("X-Real-IP")
    if x_real_ip and _is_valid_ip(x_real_ip):
        result["client_ip"] = x_real_ip
        result["is_behind_proxy"] = True
        return result

    # 直接连接
    if request.client and request.client.host:
        client_ip = request.client.host
        if _is_valid_ip(client_ip):
            result["client_ip"] = client_ip

    return result


def _is_valid_ip(ip: str) -> bool:
    """
    验证 IP 地址是否有效

    Args:
        ip: IP 地址字符串

    Returns:
        bool: 是否为有效 IP 地址
    """
    try:
        ipaddress.ip_address(ip)
        return True
    except ValueError:
        return False


def is_private_ip(ip: str) -> bool:
    """
    检查 IP 地址是否为私有地址

    Args:
        ip: IP 地址字符串

    Returns:
        bool: 是否为私有 IP 地址
    """
    try:
        ip_obj = ipaddress.ip_address(ip)
        return ip_obj.is_private
    except ValueError:
        return False


def is_public_ip(ip: str) -> bool:
    """
    检查 IP 地址是否为公网地址

    Args:
        ip: IP 地址字符串

    Returns:
        bool: 是否为公网 IP 地址
    """
    try:
        ip_obj = ipaddress.ip_address(ip)
        return not ip_obj.is_private
    except ValueError:
        return False


#########################################################
# 纯真ip库自动更新,每天自动更新纯真ip库,最新纯真免费ip库
# 下载地址:
# URL_ADDRESS# https://github.com/nmgliangwei/qqwry
# 下载后解压,将qqwry.dat文件放在data目录下
#########################################################

# 全局 QQwry 实例，避免重复加载
_QQWRY_INSTANCE = None
_QQWRY_DATABASE_PATH = "data/qqwry.dat"


def _get_qqwry_instance() -> QQwry:
    """
    获取 QQwry 实例（单例模式）

    Returns:
        QQwry: QQwry 实例
    """
    global _QQWRY_INSTANCE
    if _QQWRY_INSTANCE is None:
        _QQWRY_INSTANCE = QQwry()
        if os.path.exists(_QQWRY_DATABASE_PATH):
            _QQWRY_INSTANCE.load_file(_QQWRY_DATABASE_PATH)
        else:
            raise FileNotFoundError(f"QQwry 数据库文件不存在: {_QQWRY_DATABASE_PATH}")
    return _QQWRY_INSTANCE


@lru_cache(maxsize=1000)
def get_ip_geolocation_info(ip: str) -> dict:
    """
    获取 IP 地址的地理位置信息（优化版本）

    使用本地 QQwry 数据库查询 IP 地理位置信息，支持缓存和错误处理

    Args:
        ip: IP 地址字符串

    Returns:
        dict: 地理位置信息，包含以下字段：
            - ip: IP 地址
            - is_private: 是否为私有 IP
            - is_public: 是否为公网 IP
            - country: 国家/地区
            - region: 省份/地区
            - city: 城市
            - isp: 运营商信息
            - source: 数据来源
            - success: 查询是否成功
            - error: 错误信息（如果查询失败）

    Raises:
        FileNotFoundError: 当 QQwry 数据库文件不存在时
        ValueError: 当 IP 地址格式无效时
    """
    # 验证 IP 地址格式
    if not _is_valid_ip(ip):
        raise ValueError(f"无效的 IP 地址格式: {ip}")

    try:
        # 获取 QQwry 实例
        qqwry_instance = _get_qqwry_instance()

        # 查询 IP 地理位置信息
        country, isp = qqwry_instance.lookup(ip)

        # 处理查询结果
        if country is None:
            country = "Unknown"
        if isp is None:
            isp = "Unknown"

        # 解析国家、地区、城市信息
        country_name, region, city = _parse_location_info(country, isp)

        return {
            "ip": ip,
            "is_private": is_private_ip(ip),
            "is_public": is_public_ip(ip),
            "country": country_name,
            "region": region,
            "city": city,
            "isp": isp,
            "source": "QQwry Local Database",
            "success": True,
            "error": None,
        }

    except Exception as e:
        # 查询失败时的降级处理
        return {
            "ip": ip,
            "is_private": is_private_ip(ip),
            "is_public": is_public_ip(ip),
            "country": "Unknown",
            "region": "Unknown",
            "city": "Unknown",
            "isp": "Unknown",
            "source": "Fallback",
            "success": False,
            "error": str(e),
        }


def _parse_location_info(country: str, isp: str, split_str: str = "–") -> tuple[str, str, str]:
    """
    解析地理位置信息

    QQwry 数据库返回的国家和运营商信息可能包含地区信息
    例如："中国 广东省 深圳市 电信"

    Args:
        country: 国家信息
        isp: 运营商信息
        split_str: 分隔符，默认为 "–"

    Returns:
        tuple: (国家, 地区, 城市)
    """
    if country == "Unknown" or not country:
        return "Unknown", "Unknown", "Unknown"

    # 尝试从国家信息中解析地区
    parts = country.split(split_str)
    if len(parts) >= 3:
        # 格式：国家 省份 城市
        country_name = parts[0]
        region = parts[1] if len(parts) > 1 else "Unknown"
        city = parts[2] if len(parts) > 2 else "Unknown"
    elif len(parts) == 2:
        # 格式：国家 省份
        country_name = parts[0]
        region = parts[1]
        city = "Unknown"
    else:
        # 只有国家信息
        country_name = country
        region = "Unknown"
        city = "Unknown"

    return country_name, region, city


def update_qqwry_database(new_database_path: str) -> bool:
    """
    更新 QQwry 数据库文件

    Args:
        new_database_path: 新的数据库文件路径

    Returns:
        bool: 更新是否成功
    """
    global _QQWRY_INSTANCE
    try:
        if os.path.exists(new_database_path):
            # 重新加载数据库
            _QQWRY_INSTANCE = None
            _get_qqwry_instance()
            return True
        return False
    except Exception:
        return False


def get_qqwry_database_info() -> dict:
    """
    获取 QQwry 数据库信息

    Returns:
        dict: 数据库信息
    """
    try:
        qqwry_instance = _get_qqwry_instance()
        return {
            "database_path": _QQWRY_DATABASE_PATH,
            "database_exists": os.path.exists(_QQWRY_DATABASE_PATH),
            "database_size": os.path.getsize(_QQWRY_DATABASE_PATH) if os.path.exists(_QQWRY_DATABASE_PATH) else 0,
            "first_ip": qqwry_instance.get_first_ip(),
            "last_ip": qqwry_instance.get_last_ip(),
            "total_records": qqwry_instance.get_total_records(),
        }
    except Exception as e:
        return {
            "database_path": _QQWRY_DATABASE_PATH,
            "database_exists": False,
            "database_size": 0,
            "first_ip": "Unknown",
            "last_ip": "Unknown",
            "total_records": 0,
            "error": str(e),
        }


if __name__ == "__main__":
    # 示例用法
    ip = "220.168.52.211"
    info = get_ip_geolocation_info(ip)
    print(info)
